package angels.client.Listeners;

import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;

public class BlockingLocationListener implements LocationListener {

    final LocationManager locMngr;
    volatile Location location;
    float accuracyThreshold;
    Object syncObj;
    Handler handler;

    public BlockingLocationListener(LocationManager locMngr) {
        this.locMngr = locMngr;
        this.syncObj = new Object();
        this.handler = new Handler();
    }
    
    public Location blockingGetLocation(long timeout, float accuracyThreshold) {
        
        if (!locMngr.isProviderEnabled(LocationManager.GPS_PROVIDER))
            return null;
        
        this.accuracyThreshold = accuracyThreshold;
        
        handler.post(startLocationListener);
        
        long start = System.currentTimeMillis();
        
        location = null;
        
        // Wait for Main looper thread to give us a location 
        synchronized (syncObj) {
            // while no timeout and no accurate reading, wait...
            while ((timeout == -1 || System.currentTimeMillis() - start < timeout) && location == null) 
                try {
                    syncObj.wait(timeout + 1000);
                } 
                catch (Exception e) {}
        }
        
        locMngr.removeUpdates(this); // done with GPS
        
        return location;
    }
    
    public Location getLastKnownLocation() {
        return location;
    }

    private Runnable startLocationListener = new Runnable() {
        
        public void run() 
        {
            // MUST BE CALLED FROM A LOOPER THREAD
            locMngr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 500, 0, BlockingLocationListener.this,
                    Looper.getMainLooper());
        }
    };
    
    
    public void onLocationChanged(Location location) 
    {
        if (location.getAccuracy() > accuracyThreshold)
            return; // keep going until accuracy threshold is reached, or until timeout
        
        this.location = location;
        
        synchronized (syncObj) {
            syncObj.notifyAll();
        }
    }

    public void onProviderDisabled(String provider)  { }

    public void onProviderEnabled(String provider) { }

    public void onStatusChanged(String provider, int status, Bundle extras) { }
}
